﻿#region Header
// Copyright 2007-2011, Jerónimo Milea
// 
// This file is part of NetJsWire.
// 
//     NetJsWire is free software: you can redistribute it and/or modify
//     it under the terms of the GNU General Public License as published by
//     the Free Software Foundation, either version 3 of the License, or
//     (at your option) any later version.
// 
//     NetJsWire is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU General Public License for more details.
// 
//     You should have received a copy of the GNU General Public License
//     along with NetJsWire.  If not, see <http://www.gnu.org/licenses/>.
#endregion
#region Using

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing.Design;
using System.Threading;
using System.Windows.Forms;
using NetJsWire.JsonRpcHandler;
using NetJsWire.JsonRpcHandler.Attributes;
using NetJsWire.JsonRpcHandler.Util;
using NetJsWire.Util;
using NetJsWire.Widgets.Config;
using NetJsWire.Widgets.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Message = NetJsWire.Widgets.Core.Message;

#endregion

namespace NetJsWire.Widgets.Ui.Table
{
    /// <summary>
    ///   Table (grid) base class.
    /// </summary>
    [Renderer( typeof( Renderers.Table.Table ) )]
    public partial class Table : DataGridView, IWidget
    {
        internal Dictionary<int, int> ClientRowIndexes = new Dictionary<int, int>();
        internal InternalChange InternalChange;
        internal bool IsInternalChange;
        private string _autoExpandColumn;
        private ToolBar.ToolBar _bBar;
        private PanelConfigOptions _configOptions;
        private Dictionary<int, string> _customRenderers = new Dictionary<int, string>();
        private bool _enableColumnHide = true;

        private string _expanderTemplate;

        private string _groupBy;
        private string _groupTextTpl = "{text} ({[values.rs.length]} {[values.rs.length > 1 ? \"Items\" : \"Item\"]})";
        private int _pageSize = 25;
        private object _parent;
        private bool _remoteLoad;
        private IRenderer _renderer;
        private bool _selecting;
        private Dictionary<int, string> _summaryRenderers = new Dictionary<int, string>();
        private Dictionary<int, string> _summaryTypes = new Dictionary<int, string>();
        private ToolBar.ToolBar _tBar;
        private bool _trackSelectionChanges = true;
        private bool _useBbar;
        private bool _useRowExpander;

        private bool _useTopBar;
        private GridView _view;
        private ViewType _viewType = ViewType.Normal;

        /// <summary>
        ///   Default constructor.
        /// </summary>
        public Table()
        {
            InitializeComponent();
            _parent = Parent;

            _renderer = Helper.GetRenderer( this );
            SelectionChange += GridSelectionChange;

            ParentChanged += TableParentChanged;

            Afteredit += TableAfteredit;
            ClientKeyPress += TableKeyPress;
            ColumnHiddenChanged += TableColumnHiddenChanged;
            DataError += TableDataError;
        }

        /// <summary>
        ///   Default constructor with container setup.
        /// </summary>
        public Table( IContainer container )
            : this()
        {
            container.Add( this );
        }

        [Editor(
           "System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
           , typeof( UITypeEditor ) )]
        [DefaultValue( "" )]
        [TypeConverter(
           "System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
           )]
        [Description( "The column to autoexpand (this only has effect if ForceFit is true)." ), Category( "Data" )]
        public string AutoExpandColumn
        {
            get { return _autoExpandColumn; }
            set
            {
                if ( value != _autoExpandColumn && !string.IsNullOrEmpty( value ) )
                {
                    if ( !Renderer.Rendered )
                    {
                        Renderer.SetConstructionProperty( "autoExpandColumn", value );
                    }
                    else
                    {
                        Renderer.CallCommand( "autoExpandColumn", value );
                    }
                }
                _autoExpandColumn = value;
            }
        }

        [Description( "The selection mode this table will use." ), Category( "Selection" ),
         DefaultValue( SelectionModel.RowSelectionModel )]
        public SelectionModel SelectionModel { get; set; }

        [Editor(
           "System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
           , typeof( UITypeEditor ) )]
        [DefaultValue( "" )]
        [TypeConverter(
           "System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
           )]
        [Description( "The column to group on." ), Category( "Grouping" )]
        public string GroupColumn
        {
            get { return _groupBy; }
            set { _groupBy = value; }
        }

        /// <summary>
        ///   The value for the group header template.
        /// </summary>
        [DefaultValue( "{text} ({[values.rs.length]} {[values.rs.length > 1 ? \"Items\" : \"Item\"]})" )]
        [Description( "The value for the group header template." ), Category( "Grouping" )]
        public string GroupTextTemplate
        {
            get { return _groupTextTpl; }
            set { _groupTextTpl = value; }
        }

        /// <summary>
        ///   The collection of SummaryTypes assigned to the cells.
        ///   <example>
        ///     Example: <code>table1.SummaryTypes.Add(1, "count");</code>
        ///   </example>
        ///   <list type = "bullet">
        ///     <listheader>Summary Types:</listheader>
        ///     <item>count</item>
        ///     <item>sum</item>
        ///     <item>max</item>
        ///     <item>min</item>
        ///     <item>average</item>
        ///   </list>
        /// </summary>
        /// <remarks>
        ///   The column collection starts at index 1, the index 0 is used internally.
        /// </remarks>
        [Description( "The collection of SummaryTypes assigned to the cells." ), Category( "Grouping" )]
        public Dictionary<int, string> SummaryTypes
        {
            get { return _summaryTypes; }
            set { _summaryTypes = value; }
        }

        [Description( "The collection of SummaryRenderers assigned to the cells." ), Category( "Grouping" )]
        public Dictionary<int, string> SummaryRenderers
        {
            get { return _summaryRenderers; }
            set { _summaryRenderers = value; }
        }

        /// <summary>
        ///   Indicates that you can use summarys in your groups, the summarys can be configured with <see cref = "SummaryTypes" /> and <see cref = "SummaryRenderers" />.
        /// </summary>
        [Description( "If true use summarys for the Table groups." ), Category( "Grouping" ), DefaultValue( false )]
        public bool UseGroupSummary { get; set; }

        /// <summary>
        ///   Indicates that you will use summarys in your grid, the summarys can be configured with <see cref = "SummaryTypes" /> and <see cref = "SummaryRenderers" />.
        /// </summary>
        [Description( "If true use summarys for the Table totals." ), Category( "Grouping" ), DefaultValue( false )]
        public bool UseGridSummary { get; set; }

        /// <summary>
        ///   The title for the grid.
        /// </summary>
        [Description( "The title for the grid (notice that you cant see at design time)." ), Category( "Layout" ),
         DefaultValue( ( string ) null )]
        public string Title { get; set; }

        //TODO: Still needs some work

        [DefaultValue( false )]
        public bool RemoteLoad
        {
            get { return _remoteLoad; }
            set { _remoteLoad = value; }
        }

        [DefaultValue( false )]
        public bool GroupsStartCollapsed { get; set; }

        [DefaultValue( false )]
        public bool RemoteSort { get; set; }

        public Dictionary<int, string> CustomRenderers
        {
            get { return _customRenderers; }
            set { _customRenderers = value; }
        }

        /// <summary>
        ///   If true the grid wiil have a surrounding frame with drop shadow.
        /// </summary>
        [Description( "When true the grid will have a surrounding frame with drop shadow." ), DefaultValue( false )]
        public bool Frame { get; set; }

        [DefaultValue( false ), Category( "View" ),
         Description( "If the grid should allways fit the columns to its size." )]
        public bool ForceFit { get; set; }

        [DefaultValue( false ), Category( "View" ),
         Description( "If true the grid use a RowExpander plugin, remember to include RowExpander.js." )]
        public bool UseRowExpander
        {
            get { return _useRowExpander; }
            set
            {
                _useRowExpander = value;
                if ( !Renderer.Rendered )
                    Renderer.SetConstructionProperty( "useRowExpander", value );
            }
        }

        [DefaultValue( ( string ) null ), Category( "View" ), Description( "The template for RowExpander." )]
        public string RowExpanderTemplate
        {
            get { return _expanderTemplate; }
            set
            {
                _expanderTemplate = value;
                if ( !Renderer.Rendered )
                    Renderer.SetConstructionProperty( "rowExpanderTemplate", value );
            }
        }

        [DefaultValue( true )]
        public bool EnableColumnHide
        {
            get { return _enableColumnHide; }
            set
            {
                if ( !Renderer.Rendered )
                {
                    Renderer.SetConstructionProperty( "enableColumnHide", value );
                }
                else
                {
                    Renderer.SetEqualProperty( "enableColumnHide", value );
                }
                _enableColumnHide = value;
            }
        }

        [DefaultValue( ViewType.Normal ), RefreshProperties( RefreshProperties.All ), Category( "View" )]
        public ViewType ViewType
        {
            get { return _viewType; }
            set
            {
                if ( _viewType != value )
                {
                    if ( value == ViewType.Normal && _view != null && _view is GroupingView )
                        _view = new GridView( _view );
                    else if ( value == ViewType.Grouping && _view != null )
                        _view = new GroupingView( _view );
                }
                else
                {
                    if ( value == ViewType.Normal && _view == null )
                        _view = new GridView( _view );
                    else if ( value == ViewType.Grouping && _view == null )
                        _view = new GroupingView( _view );
                }
                _viewType = value;
            }
        }

        [RefreshProperties( RefreshProperties.All ),
         DesignerSerializationVisibility( DesignerSerializationVisibility.Visible ), Category( "View" )]
        public GridView View
        {
            get
            {
                if ( _view == null )
                {
                    if ( _viewType == ViewType.Normal )
                        _view = new GridView();
                    else if ( _viewType == ViewType.Grouping )
                        _view = new GroupingView();
                }
                return _view;
            }
            set
            {
                _view = value;

                if ( value is GroupingView )
                    _viewType = ViewType.Grouping;
                else
                    _viewType = ViewType.Normal;
            }
        }

        /*
        private StoreType _storeType = StoreType.Normal;

        [DefaultValue( StoreType.Normal ), RefreshProperties( RefreshProperties.All ), Category( "Data" )]
        public StoreType StoreType
        {
            get { return _storeType; }
            set
            {
                if ( _storeType != value )
                {
                    if ( value == StoreType.Normal && _store != null && _store is Data.DirectStore )
                    {
                        _store = new Data.Store( Container );
                        ( ( Data.Store ) _store ).DataSource = DataSource;
                    }
                    else if ( value == StoreType.Direct && _store != null && _store is Data.Store )
                    {
                        _store = new Data.DirectStore( Container );
                        ( ( Data.DirectStore ) _store ).DataSource = DataSource;
                    }
                }
                else
                {
                    if ( _store == null )
                    {
                        if ( value == StoreType.Normal )
                            _store = new Data.Store( Container );
                        else
                            _store = new Data.DirectStore( Container );
                    }
                }
                _storeType = value;
            }
        }

        private IDataStore _store;
        [RefreshProperties( RefreshProperties.All ),
         DesignerSerializationVisibility( DesignerSerializationVisibility.Visible ), Category( "Data" )]
        public IDataStore Store
        {
            get
            {
                if ( _store == null )
                {
                    if ( _storeType == StoreType.Normal )
                        _store = new Data.Store( Container );
                    else
                        _store = new Data.DirectStore( Container );
                }
                return _store;
            }
            set
            {
                _store = value;
                if ( value is Data.Store )
                {
                    _storeType = StoreType.Normal;
                }
                else
                {
                    _storeType = StoreType.Direct;
                }
            }
        }
        */

        /// <summary>
        ///   If false the element wont be shown.
        /// </summary>
        public new bool Visible
        {
            get { return base.Visible; }
            set
            {
                if ( Renderer.Rendered )
                {
                    Renderer.AddCommand( "setVisible", value );
                }
                else
                {
                    Renderer.SetConstructionProperty( "hidden", !value );
                }

                base.Visible = value;
            }
        }

        [DefaultValue( false ), RefreshProperties( RefreshProperties.All )]
        public bool UseTopBar
        {
            get { return _useTopBar; }
            set
            {
                _useTopBar = value;
                if ( _useTopBar && _tBar == null )
                {
                    TopBar = new ToolBar.ToolBar();
                    TopBar.Name = Renderer.ClientID + "_tBar";
                }
            }
        }

        [RefreshProperties( RefreshProperties.All ), DefaultValue( null )]
        public ToolBar.ToolBar TopBar
        {
            get { return _tBar; }
            set
            {
                //This is because if we had a tBar autocreated we need to remove it from WeApplication objects collection
                if ( _tBar != null )
                {
                    //WebApplication.Instance.Objects.Remove(tBar.Renderer
                    _tBar.Dispose();
                }
                _tBar = value;
                if ( _tBar != null )
                {
                    _tBar.IsInPanel = true;
                    //if(!this.Controls.Contains(_tBar  ))
                    //{
                    //    _tBar.Dock = DockStyle.Top;
                    //    this.Controls.Add( _tBar );
                    //}
                }
            }
        }

        [DefaultValue( false ), RefreshProperties( RefreshProperties.All )]
        public bool UseBbar
        {
            get { return _useBbar; }
            set
            {
                _useBbar = value;
                if ( _useBbar && _bBar == null )
                {
                    BottomBar = new ToolBar.ToolBar();
                    BottomBar.Name = Renderer.ClientID + "_tBar";
                }
            }
        }

        [RefreshProperties( RefreshProperties.All ), DefaultValue( null )]
        public ToolBar.ToolBar BottomBar
        {
            get { return _bBar; }
            set
            {
                //This is because if we had a bBar autocreated we need to remove it from WeApplication objects collection
                if ( _bBar != null )
                {
                    _bBar.Dispose();
                }
                _bBar = value;
                if ( _bBar != null )
                {
                    _bBar.IsInPanel = true;
                    //if ( !this.Controls.Contains( _bBar ) )
                    //{
                    //    _bBar.Dock = DockStyle.Bottom;
                    //    this.Controls.Add( _bBar );
                    //}
                }
            }
        }

        [DesignerSerializationVisibility( DesignerSerializationVisibility.Content ),
         Editor( "NetJsWire.Widgets.Ui.Table.TableColumnCollectionEditor", typeof( UITypeEditor ) ),
         MergableProperty( false )]
        public new DataGridViewColumnCollection Columns
        {
            get { return base.Columns; }
        }

        internal bool HasSortRequestHandled
        {
            get
            {
                var sr = SortRequest;
                return sr != null;
            }
        }

        public string FieldLabel { get; set; }

        public bool TrackSelectionChanges
        {
            get { return _trackSelectionChanges; }
            set { _trackSelectionChanges = value; }
        }

        /// <summary>
        ///   The amount of items that will be shown in each page when RemoteLoad = true
        /// </summary>
        [DefaultValue( 25 )]
        public int PageSize
        {
            get { return _pageSize; }
            set { _pageSize = value; }
        }

        #region IWidget Members

        [Browsable( false ), EditorBrowsable( EditorBrowsableState.Advanced )]
        public IRenderer Renderer
        {
            get { return _renderer; }
        }

        public void On( string name, string function )
        {
            Renderer.AddClientEvent( name, function );
        }

        public void AddClass( string cls )
        {
            Renderer.AddCommand( "addClass", cls );
        }

        public void RemoveClass( string cls )
        {
            Renderer.AddCommand( "removeClass", cls );
        }

        [DefaultValue( false )]
        [Description( "If the framework should generate a global Javascript variable that points to the Widget, the name of the variable will be the same as ClientID property of the Renderer." )]
        public bool GenerateClientMember { get; set; }

        [RefreshProperties( RefreshProperties.All ),
         DesignerSerializationVisibility( DesignerSerializationVisibility.Content ), Category( "Config" )]
        public IConfigOptions ConfigOptions
        {
            get
            {
                if ( _configOptions == null )
                {
                    _configOptions = new PanelConfigOptions( this );
                }
                return _configOptions;
            }
        }

        #endregion

        public event EventHandler SelectionChange;
        public event EventHandler ClientKeyPress;
        public event EventHandler ColumnHiddenChanged;
        public new event EventHandler KeyPress;
        internal event EventHandler DataRequestedFromClient;
        public event EventHandler Afteredit;
        public event EventHandler RowDoubleClick;
        public new event EventHandler CellDoubleClick;
        public event EventHandler Custom;
        public event EventHandler SortRequest;

        private static void TableDataError( object sender, DataGridViewDataErrorEventArgs e )
        {
            Message.Show( "Error",
                          "Hubo un error al establecer el valor.<br />" + e.Exception.Message + "<br />" +
                          e.Exception.StackTrace, 5, MessageType.Error );
            e.ThrowException = false;
        }

        private void TableColumnHiddenChanged( object sender, EventArgs e )
        {
            IsInternalChange = true;
            try
            {
                int colIndex;
                bool hidden;
                var o = ( JArray ) sender;

                int.TryParse( o[ 0 ].ToString(), out colIndex );
                bool.TryParse( o[ 1 ].ToString(), out hidden );

                colIndex--; // The RowIndex column doesnt exists in the grid

                if ( colIndex >= 0 )
                {
                    Columns[ colIndex ].Visible = !hidden;
                }
            }
            finally
            {
                IsInternalChange = false;
            }
        }

        private void TableParentChanged( object sender, EventArgs e )
        {
            // Si _parent es null es porque no había sido agregada a un contenedor
            if ( !Disposing && Parent != null && _parent != null )
            {
                if ( _renderer != null )
                {
                    WebApplication.Instance.RemoveObject( ( ( Renderers.Table.Table ) Renderer ).InternalID );
                }

                _renderer = Helper.GetRenderer( this );
            }

            _parent = Parent;
        }

        private void TableAfteredit( object sender, EventArgs e )
        {
            IsInternalChange = true;
            var o = ( JArray ) sender;
            int row;
            int col;
            if ( int.TryParse( o[ 0 ].ToString(), out row ) )
            {
                if ( ClientRowIndexes.ContainsKey( row ) )
                {
                    row = ClientRowIndexes[ row ];
                }
                else
                {
                    row = -1;
                }
            }
            //var rId = o[ 0 ].ToString();
            //int.TryParse( o[ 0 ].ToString(), out row );
            //row = _clientRowIndexes.IndexOf( rId );
            int.TryParse( o[ 1 ].ToString(), out col );
            //object value = o[2];
            col -= 1; // The RowIndex column doesn't exists in the grid
            if ( row >= 0 && col >= 0 && row < Rows.Count && col < Columns.Count )
            {
                InternalChange = new InternalChange();
                InternalChange.Row = row;
                InternalChange.Col = col;

                object val;
                if ( Rows[ row ].Cells[ col ].ValueType == typeof( DateTime ) )
                {
                    var tmp = o.Value<string>( 2 ).Split( 'T' )[ 0 ].Split( '-' );
                    //Discard the time part and get the values
                    var year = int.Parse( tmp[ 0 ] );
                    var month = int.Parse( tmp[ 1 ] );
                    var day = int.Parse( tmp[ 2 ] );
                    var dt = new DateTime( year, month, day );
                    val = dt;
                    InternalChange.Value = val;
                    Rows[ row ].Cells[ col ].Value = val;
                }
                else
                {
                    var nonDeserializedValue = o.Value<object>( 2 );

                    if ( nonDeserializedValue is bool )
                    {
                        val = ( bool ) nonDeserializedValue;
                    }
                    else if ( nonDeserializedValue is string )
                    {
                        val = nonDeserializedValue;
                    }
                    else
                    {
                        if ( Rows[ row ].Cells[ col ].ValueType != null )
                        {
                            if ( Rows[ row ].Cells[ col ].ValueType == typeof( object ) )
                            {
                                val = nonDeserializedValue;
                            }
                            else
                            {
                                val = JsonConvert.DeserializeObject( o.Value<string>( 2 ),
                                                                     Rows[ row ].Cells[ col ].ValueType );
                            }
                        }
                        else
                            val = JsonConvert.DeserializeObject( o.Value<string>( 2 ) );
                    }
                    //val = o.GetValue( 2 ); //Jayrock.Json.Conversion.JsonConvert.Import(o.GetString(2));
                    InternalChange.Value = val;
                    Rows[ row ].Cells[ col ].Value = val;
                }
            }
            WebApplication.Instance.HasChanges = true;
            IsInternalChange = false;
            InternalChange = null;
        }

        public void SetCellValue( int rowIndex, int cellIndex, object value )
        {
            var oldInternalChange = IsInternalChange;
            IsInternalChange = false;
            Rows[ rowIndex ].Cells[ cellIndex ].Value = value;
            IsInternalChange = oldInternalChange;
        }

        private void TableKeyPress( object sender, EventArgs e )
        {
            if ( KeyPress != null )
            {
                while ( _selecting )
                    Thread.Sleep( 100 );

                var number = Convert.ToInt32( sender );
                KeyPress( ( object ) number, EventArgs.Empty );
            }
        }

        private void GridSelectionChange( object sender, EventArgs e )
        {
            _selecting = true;
            try
            {
                var o = ( JArray ) sender;

                Debug.WriteLine( "Setting selected row to: " + sender );
                //var selRow = _clientRowIndexes.IndexOf( o.GetString( 0 ) );
                var selRow = o.Value<int>( 0 );

                //int selRow = o.GetInt32( 0, -1 );
                if ( ClientRowIndexes.ContainsKey( selRow ) )
                {
                    selRow = ClientRowIndexes[ selRow ];
                }

                var selCol = o.Value<int>( 1 );
                if ( selRow != -1 )
                {
                    if ( Rows.Count > selRow )
                    {
                        if ( SelectedRows.Count > 0 && SelectedRows[ 0 ] != null )
                            SelectedRows[ 0 ].Selected = false;
                        Rows[ selRow ].Selected = true;
                        if ( selCol > 0 &&
                             SelectionMode == DataGridViewSelectionMode.CellSelect )
                        {
                            selCol--; // we have to do this coz col 1 on client is col 0 on server.
                            if ( Columns.Count > 0 && Columns.Count > selCol )
                                Rows[ selRow ].Cells[ selCol ].Selected = true;
                        }
                        Debug.WriteLine( "Selected row is: " + sender );
                    }
                    else if ( Rows != null && Rows.Count < selRow )
                    {
                        selRow = Rows.Count - 1;

                        if ( SelectedRows.Count > 0 && SelectedRows[ 0 ] != null )
                            SelectedRows[ 0 ].Selected = false;
                        Rows[ selRow ].Selected = true;
                        if ( selCol > 0 &&
                             SelectionMode == DataGridViewSelectionMode.CellSelect )
                        {
                            selCol--; // we have to do this coz col 1 on client is col 0 on server.
                            if ( Columns.Count > 0 && Columns.Count > selCol )
                                Rows[ selRow ].Cells[ selCol ].Selected = true;
                        }
                        Debug.WriteLine( "Selected row is: " + sender );
                    }
                    else
                    {
                        //throw new Exception("Cant select row.");
                        Debug.WriteLine( "Selected row is not set." );
                    }
                }
                else
                {
                    //throw new Exception("Cant select row.");
                    Debug.WriteLine( "Failed to parse row." );
                }
            }
            finally
            {
                _selecting = false;
            }
        }

        public void RequestGridData( NameValueCollection param )
        {
            if ( DataRequestedFromClient != null )
            {
                DataRequestedFromClient( param, EventArgs.Empty );
            }
        }

        public void RefreshData()
        {
            //ds.load({params:{start: this.cursor, limit: this.pageSize}});
            if ( Renderer.Rendered )
            {
                if ( _remoteLoad )
                {
                    //ExtJS.NET.Renderer.grid.Grid gr = (Renderer as ExtJS.NET.Renderer.grid.Grid);
                    //Renderer.AddCommand("getDataSource().load", string.Format("{{params:{{ start:{0}.ds.cursor, limit:{0}.ds.pageSize }} }}", gr.ClientId));
                    Renderer.AddCommand( "getDataSource().reload" );
                }
                else
                {
                    Renderer.AddCommand( "getDataSource().reload" );
                }
            }
        }

        public void AddKeyPressEventHandler( int key, EventHandler handler )
        {
            ( ( Renderers.Table.Table ) Renderer ).AddKeyPressEventHandler( key );
            if ( KeyPress != null )
            {
                foreach ( var del in KeyPress.GetInvocationList() )
                {
                    if ( del == handler )
                        return;
                }
            }
            KeyPress += handler;
        }

        public void SelectNextRow()
        {
            if ( ReadOnly )
                Renderer.AddCommand( "getSelectionModel().selectNext", false );
            else
                Renderer.AddCommand( "getSelectionModel().select",
                                     new object[] { SelectedRows[ 0 ].Index, Columns.Count } );
        }

        /// <summary>
        ///   Toggle the collapsed state of the groups in the Table.
        /// </summary>
        /// <param name = "state">true to expand groups.</param>
        public void ToggleAllGroups( bool state )
        {
            if ( !string.IsNullOrEmpty( _groupBy ) )
            {
                Renderer.AddCommand( "getView().toggleAllGroups", state );
            }
        }

        internal void HandleSortRequest( string sortColumn, string sortDir )
        {
            SortRequest( new object[] { sortColumn, sortDir }, EventArgs.Empty );
        }
    }
}